import NERTC from "nertc-web-sdk/NERTC"
import {createRoom, removeRoom, getRoomInfo} from "@/api/room"

const rtc = {
    appkey: "562d8698ad691f7a6ee4326505313121",
    remoteStreams: [],
    rtc: {
        client: null,
        localStream: null
    },
    isVideoCall: true,
    init({isVideoCall}) {
        this.isVideoCall = isVideoCall;
        this.rtc.client = NERTC.createClient({
            appkey: this.appkey,
            debugger: true
        })
    },
    listener({peerLeave, streamAdded, streamRemoved, streamSubscribed, peerOnline}) {
        //房间连接状态改变通知回调
        this.rtc.client.on('connection-state-change', (evt) => {

        })
        //远端用户加入房间通知回调，建议在收到此回调后再进行设置远端视图等的操作
        this.rtc.client.on('peer-online', evt => {

            peerOnline && peerOnline({uid: evt.uid})
        })
        //远端用户退出房间通知回调
        this.rtc.client.on('peer-leave', evt => {

            this.remoteStreams = this.remoteStreams.filter(
                (item) => !!item.getId() && item.getId() !== evt.uid
            );
            peerLeave && peerLeave({remoteStreams: this.remoteStreams, uid: evt.uid})
        })
        //远端用户推流/停止推流通知回调，建议在收到此回调后再进行订阅或取消订阅音视频流的操作
        this.rtc.client.on("stream-added", async (evt) => {
            const stream = evt.stream;
            const userId = stream.getId();
            console.warn(`收到 ${userId} 的发布 ${evt.mediaType} 的通知`) // mediaType为：'audio' | 'video' | 'screen'
            if (this.remoteStreams.some((item) => item.getId() === userId)) {
                console.warn('收到已订阅的远端发布，需要更新', stream);
                this.remoteStreams = this.remoteStreams.map((item) =>
                    item.getId() === userId ? stream : item
                );
                streamAdded && streamAdded({remoteStreams: this.remoteStreams})
                //订阅其发布的媒体，可以渲染播放
                await this.subscribe(stream);
            } else {
                console.warn('收到新的远端发布消息', stream);
                this.remoteStreams = this.remoteStreams.concat(stream);
                streamAdded && streamAdded({remoteStreams: this.remoteStreams})
                //订阅其发布的媒体，可以渲染播放
                await this.subscribe(stream);
            }
        });
        this.rtc.client.on('stream-subscribed', evt => {
            const userId = evt.stream.getId();
            console.warn(`收到订阅 ${userId} 的 ${evt.mediaType} 成功的通知`) // mediaType为：'audio' | 'video' | 'screen'
            //这里可以根据mediaType的类型决定播放策略
            const remoteStream = evt.stream;
            const {remoteViews} = streamSubscribed && streamSubscribed()
            //用于播放对方视频画面的div节点
            let div = null;
            if (this.isVideoCall) {
                div = [...remoteViews].find((item) => {
                    return Number(item.dataset.uid) === Number(remoteStream.getId());
                });
            }
            //这里可以控制是否播放某一类媒体，这里设置的是用户主观意愿
            //比如这里都是设置为true，本次通知的mediaType为audio，则本次调用的play会播放音频，如果video、screen内部已经订阅成功，则也会同时播放video、screen，反之不播放
            const playOptions = {
                audio: true,
                video: this.isVideoCall,
                screen: false
            }
            remoteStream.play(div, playOptions).then(() => {
                ;
                if (div) {
                    remoteStream.setRemoteRenderMode({
                        // 设置视频窗口大小
                        width: div.clientWidth,
                        height: div.clientHeight,
                        cut: false, // 是否裁剪
                    });
                }
            }).catch((err) => {
                console.warn('播放对方视频失败了: ', err);
            });
            //这里监听一下音频自动播放会被浏览器限制的问题（https://doc.yunxin.163.com/nertc/docs/jM3NDE0NTI?platform=web）
            remoteStream.on('notAllowedError', (err) => {
                const errorCode = err.getCode();
                const id = remoteStream.getId();
                ;
                if (errorCode === 41030) {
                    //页面弹筐加一个按钮，通过交互完成浏览器自动播放策略限制的接触
                    const userGestureUI = document.createElement('div')
                    if (userGestureUI && userGestureUI.style) {
                        userGestureUI.style.fontSize = '20px';
                        userGestureUI.style.position = 'fixed';
                        userGestureUI.style.background = 'yellow';
                        userGestureUI.style.margin = 'auto';
                        userGestureUI.style.width = '100%';
                        userGestureUI.style.zIndex = '9999';
                        userGestureUI.style.top = '0';
                        userGestureUI.onclick = () => {
                            if (userGestureUI && userGestureUI.parentNode) {
                                userGestureUI.parentNode.removeChild(userGestureUI);
                            }
                            remoteStream.resume();
                        }
                        userGestureUI.style.display = 'block';
                        userGestureUI.innerHTML = '自动播放受到浏览器限制，需手势触发。<br/>点击此处手动播放'
                        document.body.appendChild(userGestureUI)
                    }
                }
            });
        })
        this.rtc.client.on("stream-removed", (evt) => {
            const stream = evt.stream;
            const userId = stream.getId();
            console.warn(`收到 ${userId} 的停止发布 ${evt.mediaType} 的通知`) // mediaType为：'audio' | 'video' | 'screen'
            stream.stop(evt.mediaType);
            this.remoteStreams = this.remoteStreams.map((item) =>
                item.getId() === userId ? stream : item
            );
            console.warn('远端流停止订阅，需要更新', userId, stream);
            streamRemoved && streamRemoved({remoteStreams: this.remoteStreams})
        });
        //网络质量通知回调（请列出所有枚举）
        this.rtc.client.on('network-quality', stats => {

            let status = null
            stats.forEach(item => {
                status = 'uid: ' + item.uid + ',上行：' + item.uplinkNetworkQuality + ',下行：' + item.downlinkNetworkQuality

            })
        })
    },
    createRoom({eventId}) {
        return createRoom({eventId})
    },
    removeRoom({cname}) {
        return removeRoom({cname})
    },
    getRoomInfo({cname}) {
        return getRoomInfo({cname})
    },
    join({channelName, uid, token, viewId}) {
        //加入房间
        this.rtc.client.join({
            channelName,
            uid,
            token //调试模式下可设置为 null。正式上线前设置为相应的 Token，具体请参考 "Token 鉴权" 章节。
        }).then(() => {
            console.info('加入房间成功...')
            //初始化本地流，并且发布
            this.initLocalStream({uid, viewId}) //后面介绍说明
        })
    },
    async leave() {
        try {
            // 使用 await 等待 leave 方法完成
            await this.rtc.client.leave();
            ;
        } catch (error) {
            // 处理 leave 方法可能抛出的异常
            console.error('离开房间失败', error);
        }
    },
    destroy() {
        if (this.rtc.localStream) {
            this.rtc.localStream.destroy()
            this.rtc.localStream = null
        }
        if (this.rtc.client) {
            this.rtc.client.destroy()
            this.rtc.client = null
            this.remoteStreams = []
        }
    },
    async initLocalStream({viewId, uid}) {
        const cameras = await NERTC.getCameras();    //获取可用的视频输入设备
        const microphones = await NERTC.getMicrophones();     //获取可用的麦克风设备
        //创建本端 stream 实例，销毁前无需重复创建
        this.rtc.localStream = NERTC.createStream({
            uid: uid,                      // 本端的 uid
            audio: true,                   // 是否从麦克风采集音频
            microphoneId: microphones.microphoneId,    // 麦克风设备 deviceId，通过 getMicrophones() 获取
            video: this.isVideoCall,                   // 是否从摄像头采集视频
            cameraId: cameras.cameraId             // 摄像头设备 deviceId，通过 getCameras() 获取
        })

        //启动本地音视频流，销毁前无需重复初始化
        this.rtc.localStream.init().then(() => {
            console.warn('音视频初始化完成，播放本地视频')
            //用于播放视频的 div 元素
            let div = document.getElementById(viewId)
            //开始播放本地视频流
            this.rtc.localStream.play(div)
            //设置播放的视频容器大小
            this.rtc.localStream.setLocalRenderMode({
                width: div.clientWidth,
                height: div.clientHeight,
                cut: true    // 是否裁剪
            })

            // 将本地音视频流发布至网易云信服务器，加入房间前不用执行此方法。
            this.rtc.client.publish(this.rtc.localStream).then(() => {
                console.warn('本地 publish 成功')
            })
        })
    },
    subscribe(remoteStream) {
        //这里可以控制是否订阅某一类媒体，这里设置的是用户主观意愿
        //比如这里都是设置为true，如果stream-added事件中通知了是audio发布了，则本次调用会订阅音频，如果video、screen之前已经有stream-added通知，则也会同时订阅video、screen，反之会忽略
        remoteStream.setSubscribeConfig({
            audio: true,
            video: this.isVideoCall,
            screen: false
        });
        this.rtc.client
            .subscribe(remoteStream)
            .then(() => {
                console.warn('本地 subscribe 成功');
            })
            .catch((err) => {
                console.warn('本地 subscribe 失败: ', err);
                message('订阅对方的流失败');
            });
    }
}

export default rtc
